import type { CustomPopupOptions } from '@/layouts/useUi'
import { useUi } from '../../manager'

/**
 * 纯文本轻提示显示位置，填写有效值后只有 title 属性生效
 * - top: 居上显示
 * - center: 居中显示
 * - bottom: 居底显示
 */
type ToastPosition = 'top' | 'center' | 'bottom'

type LoadingType = Omit<UniApp.ShowLoadingOptions, 'title'> & { sys?: boolean }
interface ModelType {
  sys?: boolean
  show?: boolean
  title?: string
  content?: string
  showCancel?: boolean
  showConfirm?: boolean
  cancelText?: string
  confirmText?: string
  contentStyle?: string
  hideOnBlur?: boolean
  autoClose?: boolean
  cancelHandler?: () => void
  confirmHandler?: () => void
}
/**
 * toast弹窗
 * @param {string} title - 消息
 * @param {string} pos "bottom" | "top" | "center" | undefined - 位置
 * @param {object} param - 其它参数同官方
 * @return {Promise<undefined>}
 */
export function toast(title: string = '', pos: ToastPosition = 'bottom', { duration = 1500, icon = 'none', mask = false, ...param } = {} as any): Promise<unknown> | undefined {
  if (!title) return
  const ui = useUi()
  if (param.sys || ui.useSys) {
    uni.showToast({
      title,
      position: pos,
      duration,
      mask,
      icon,
      ...param
    })
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve(true)
      }, duration)
    })
  }
  return ui.toast(title, { mask, duration, icon: icon === 'none' ? '' : icon })
}
/**
 * 隐藏toast弹窗
 */
export function hideToast(useSys: boolean = false) {
  const ui = useUi()
  if (useSys || ui.useSys) {
    uni.hideToast()
    return
  }
  ui.hideToast()
}
/**
 * loading弹窗
 * @param {string} title - 消息
 * @param {object} param - 其它参数同官方
 * @return {Promise<any>}
 */
export function showLoading(title: string = '', param = {} as LoadingType): any {
  if (!title) return
  const ui = useUi()
  if (param.sys || ui.useSys) {
    uni.showLoading({
      title,
      mask: param.mask || true,
      ...param
    })
    return
  }
  ui.showLoading(title, param)
}

/**
 * 隐藏loading弹窗
 * @return void
 */
export function hideLoading(useSys: boolean = false) {
  const ui = useUi()
  if (useSys || ui.useSys) {
    uni.hideLoading()
    return
  }
  ui.hideLoading()
}

/**
 * 类似alert弹窗，只有确认按钮
 * @param {string} title - 弹窗标题
 * @param {string} content - 弹窗内容
 * @param {object} param - 其它参数同官方
 * @return {Promise<UniApp.ShowModalRes>}
 */
export function alert({ sys = false, title = '温馨提示', content = '', ...options } = {} as ModelType) {
  const ui = useUi()
  if (sys || ui.useSys) {
    uni.showModal(Object.assign({
      title,
      content,
      confirmColor: ui.popupConfig.confirmColor || '#007AFF',
      cancelColor: ui.popupConfig.cancelColor || '#f0f0f0',
      success: (res: { confirm: boolean, cancel: boolean }) => {
        if (res.confirm) {
          options.confirmHandler && options.confirmHandler()
        }
        else if (res.cancel) {
          options.cancelHandler && options.cancelHandler()
        }
      }
    }, options, { showCancel: false }))
    return {}
  }
  options.showCancel = false
  return ui.confirm(Object.assign({
    title,
    content
  }, options))
}

/**
 * 类似confirm弹窗,具有取消和确定按钮
 * @param {string} title - 弹窗标题
 * @param {string} content - 弹窗内容
 * @param {object} param - 其它参数同官方
 * @return {Promise<UniApp.ShowModalRes>}
 */
export function confirm({ sys = false, title = '温馨提示', content = '', ...options } = {} as ModelType) {
  const ui = useUi()
  if (sys || ui.useSys) {
    uni.showModal(Object.assign({
      title,
      content,
      confirmColor: ui.popupConfig.confirmColor || '#007AFF',
      cancelColor: ui.popupConfig.cancelColor || '#f0f0f0',
      success: (res: { confirm: any, cancel: any }) => {
        if (res.confirm) {
          options.confirmHandler && options.confirmHandler()
        }
        else if (res.cancel) {
          options.cancelHandler && options.cancelHandler()
        }
      }
    }, options, { showCancel: true }))
    return {}
  }
  options.showCancel = true
  return ui.confirm(Object.assign({
    title,
    content
  }, options))
}

/**
 * 只提供弹窗，内容由开发者自定义
 * @param {string} CustomPopupOptions - 弹窗配置
 * @return {Promise<UniApp.ShowModalRes>}
 */
export function customPopup(options: CustomPopupOptions) {
  const ui = useUi()
  return ui.customPopup(options)
}

/**
 * 获取设备信息
 */
export function systemInfo(): UniApp.GetSystemInfoResult {
  return uni.getSystemInfoSync()
}
/**
 * 获取屏幕宽度
 */
export function screenWidth(): number {
  return systemInfo().screenWidth
}
/**
 * 获取屏幕高度
 */
export function screenHeight(): number {
  return systemInfo().screenHeight
}

/**
 * 获取页面栈
 * @param {number} preIndex为1时获取上一页
 * @return {object}
 */
export function prePage(preIndex = 1) {
  const pages = getCurrentPages()
  const prePage = pages[pages.length - (preIndex + 1)]
  return prePage.$vm
}

interface CopyTextRes { msg: string, code: 200 | 400, content: string }
/**
 * 复制文本内容
 * @param {string} content - 要复制的文本
 * @param {boolean} isToast - 是否显示toast,默认显示，不显示需要在回调中自行处理
 * @return {Promise<{ msg : string, code : 200 | 400, content : string }>}
 */
export function copyText(content: string | number, isToast = true): Promise<CopyTextRes> {
  if (content === '') {
    toast('复制的内容不能为空 !')
    return Promise.reject(new Error('复制的内容不能为空~'))
  }
  content = typeof content === 'string' ? content : content.toString() // 复制内容，必须字符串，数字需要转换为字符串
  /**
   * 小程序端 和 app端的复制逻辑
   */
  const suc = {
    msg: '复制成功',
    code: 200,
    content
  }
  const fail = {
    msg: '复制失败~',
    code: 400,
    content: ''
  }
  return new Promise<CopyTextRes>((resolve, reject) => {
    // #ifndef H5
    uni.setClipboardData({
      data: content,
      success: () => resolve(suc as CopyTextRes),
      fail: () => reject(fail)
    })
    // #endif
    // #ifdef H5
    if (navigator.clipboard && window.isSecureContext) {
      navigator.clipboard.writeText(content).then(() => resolve(suc as CopyTextRes)).catch((_: any) => reject(fail))
    }
    else {
      const textArea = document.createElement('textarea')
      textArea.style.opacity = '0'
      textArea.style.position = 'fixed'
      textArea.style.top = '0px'
      textArea.value = content
      textArea.readOnly = true
      document.body.appendChild(textArea)
      textArea.focus()
      textArea.select()
      textArea.setSelectionRange(0, content.length)
      try {
        document.execCommand('copy') ? resolve(suc as CopyTextRes) : reject(fail)
      }
      catch (error) {
        reject(fail)
      }
      finally {
        textArea.remove()
      }
    }
    // #endif
  }).then(res => {
    isToast && toast(res.msg)
    return res
  }).catch(err => {
    isToast && toast(err.msg)
    return err
  })
}

/**
 * 获取剪切板内容
 * @returns {Promise<string>} 剪切板内容
 */
export function getClipboardData(): Promise<any> {
  return new Promise((rs, rj) => {
    // #ifndef H5
    uni.getClipboardData({
      success: (res) => rs(res.data),
      fail: (error) => rj(error)
    })
    // #endif
    // #ifdef H5
    if (navigator.clipboard) {
      navigator.clipboard.readText().then(rs).catch(rj)
    }
    else {
      console.error('H5无法获取剪切板内容')
      rj(new Error('H5不支持获取剪切板内容'))
    }
    // #endif
  })
}

/**
 * 链接跳转
 * @param {string} url 跳转链接
 * @param {boolean} inWhiteList 如果在小程序的网址白名单中，会走内置webview打开，否则会复制网址提示在外部浏览器打开
 * @return void
 */
export function openURL(url: string, inWhiteList = true) {
  // #ifdef APP-PLUS
  plus.runtime.openURL(url) // 这里默认使用外部浏览器打开而不是内部web-view组件打开
  // #endif
  // #ifdef H5
  window.open(url)
  // #endif
  // #ifdef MP
  if (inWhiteList) { // 如果在小程序的网址白名单中，会走内置webview打开，否则会复制网址提示在外部浏览器打开
    uni.navigateTo({
      url: `/pages/component/web-view/web-view?url=${url}`
    })
  }
  else {
    copyText(url)
    toast('本网址无法直接在小程序内打开。已自动复制网址，请在手机浏览器里粘贴该网址')
  }
  // #endif
}

/**
 * 图片大图预览
 * @param {string[]} urls 单张图片地址或者多张图片地址数组 ['http://1','http://2']
 * @item {string|number} 图片下标索引或图片项 0, 1 或 http://1 ,http://2两种格式
 * @param {object} config 同uni配置
 * @return void
 */
export function previewImage(urls: string | string[], item = 0, config = {}) {
  if (!urls) return
  if (typeof urls === 'string') {
    urls = [urls]
  }
  let current = 0
  if (typeof item === 'number') {
    current = item
  }
  if (typeof item === 'string') {
    current = urls.findIndex(e => e === item)
    current = current < 0 ? 0 : current
  }
  // 预览图片
  uni.previewImage({
    urls,
    current,
    ...config
  })
}

export function selector(select: string) {
  return uni.createSelectorQuery().select(select)
}

export function getClientRect(select: string) {
  return new Promise((resolve, reject) => {
    uni.createSelectorQuery().select(select).boundingClientRect(resolve).exec()
  })
}
